#include "linux/tty.h"
#include "linux/kernel.h"
#include "string.h"
#include "linux/gdt.h"

#define FOUR_LEVEL_HEAD_TABLE_ADDR 0x8000
#define FIRST_PDPT_ADDR 0x9000
#define FIRST_PDT_ADDR 0xa000

extern void x64_cpu_check();

static void prepare_4level_page_table()
{
    int* four_level_head_table_addr = (int*) FOUR_LEVEL_HEAD_TABLE_ADDR;
    memset(four_level_head_table_addr, 0, 4096);

    *four_level_head_table_addr = FIRST_PDPT_ADDR | 3;
    *(four_level_head_table_addr + 1) = 0;

    int* pdpt_addr = (int*) FIRST_PDPT_ADDR;
    memset(pdpt_addr, 0, 4096);

    *pdpt_addr = FIRST_PDT_ADDR | 3;
    *(pdpt_addr + 1) = 0;

    int* pdt_addr = (int*) FIRST_PDT_ADDR;
    memset(pdt_addr, 0, 4096);

    for (size_t i = 0; i < 50; i++)
    {
        *(pdt_addr + i * 2) = 0x200000 * i | 0x83;
        *(pdt_addr + i * 2 + 1) = 0;
    }
    

    // 以下两行代码的执行效果是一样的，说明最终传给ebx的都是0x8000这个值。
    asm volatile("xchg bx, bx; mov cr3, ebx"::"b"(FOUR_LEVEL_HEAD_TABLE_ADDR));
    // asm volatile("xchg bx, bx; mov cr3, ebx"::"b"(four_level_head_table_addr));
    
    // 这行代码在这里竟然也能正常运行
    // install_x64_descriptor();
}

static void enter_x64()
{
    prepare_4level_page_table();
    asm volatile("xchg bx, bx; mov eax, cr4; bts eax, 5; mov cr4, eax;");
    asm volatile("mov ecx, 0x0c0000080; rdmsr; bts eax, 8; wrmsr");
    asm volatile("mov eax, cr0; or eax, 0x80000000; mov cr0, eax");

    install_x64_descriptor();

    // 0x18是64位段描述符选择子，0x100000是64位内核加载到的位置
    asm volatile("push 0x18; push 0x100000; retf");
}

void kernel_main(void)
{
    console_init();

    x64_cpu_check();
    enter_x64();

    while (true)
    {
    }
    
    
}